// ignore_for_file: use_build_context_synchronously

import 'dart:io';
import 'dart:typed_data';
import 'package:encrypt_and_decrypt_files/widget/extension.dart';
import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:pointycastle/export.dart';

class Algorithm {
  Future<bool?> encrypt({
    required BuildContext context,
    required int type,
    required String name,
    required String inputFile,
    String? encryptedFile,
    String? decryptedFile,
    required Uint8List key,
    Uint8List? iv,
  }) async {
    switch (name) {
      case 'RC2':
        await encryptAndDecryptFile(
            context,
            type,
            File(inputFile),
            encryptedFile == null ? null : File(encryptedFile),
            decryptedFile == null ? null : File(decryptedFile),
            key,
            iv,
            _createAESCipher);
        break;
      case 'AES':
        await encryptAndDecryptFile(
            context,
            type,
            File(inputFile),
            encryptedFile == null ? null : File(encryptedFile),
            decryptedFile == null ? null : File(decryptedFile),
            key,
            iv,
            _createAESCipher);
        break;
      case 'RC4':
        await encryptAndDecryptFile(
            context,
            type,
            File(inputFile),
            encryptedFile == null ? null : File(encryptedFile),
            decryptedFile == null ? null : File(decryptedFile),
            key,
            null,
            _createRC4Cipher);
        break;
      default:
        throw ArgumentError('不支持的加密类型');
    }
    return null;
  }

  Future<bool?> encryptAndDecryptFile(
    BuildContext context,
    int type,
    File inputFile,
    File? encryptedFile,
    File? decryptedFile,
    Uint8List key,
    Uint8List? iv,
    dynamic cipherFactory,
  ) async {
    try {
      final cipher = cipherFactory(key, iv);

      final inputBytes = await inputFile.readAsBytes();
      int blockSize = 16; // AES块大小
      if (type == 0) {
        // 加密
        cipher.init(
            true,
            iv == null
                ? KeyParameter(key)
                : ParametersWithIV(KeyParameter(key), iv));
        // 添加PKCS#7填充
        int paddingLength = blockSize - (inputBytes.length % blockSize);
        Uint8List paddedBytes = Uint8List(inputBytes.length + paddingLength);
        paddedBytes.setRange(0, inputBytes.length, inputBytes);
        for (int i = inputBytes.length; i < paddedBytes.length; i++) {
          paddedBytes[i] = paddingLength;
        }
        // 分块加密
        Uint8List encryptedBytes = Uint8List(paddedBytes.length);
        for (int i = 0; i < paddedBytes.length; i += blockSize) {
          int len = (paddedBytes.length - i > blockSize)
              ? blockSize
              : (paddedBytes.length - i);
          final block =
              cipher.process(Uint8List.view(paddedBytes.buffer, i, len));
          encryptedBytes.setRange(i, i + len, block);
        }
        await encryptedFile!.writeAsBytes(encryptedBytes);
      } else {
        // 解密
        cipher.init(
            false,
            iv == null
                ? KeyParameter(key)
                : ParametersWithIV(KeyParameter(key), iv));
        // 分块解密
        Uint8List decryptedBytes = Uint8List(inputBytes.length);
        for (int i = 0; i < inputBytes.length; i += blockSize) {
          int len = (inputBytes.length - i > blockSize)
              ? blockSize
              : (inputBytes.length - i);
          final block =
              cipher.process(Uint8List.view(inputBytes.buffer, i, len));
          decryptedBytes.setRange(i, i + len, block);
        }
        // 移除PKCS#7填充
        int paddingLength = decryptedBytes[decryptedBytes.length - 1];
        if (paddingLength < 1 || paddingLength > 16) {
          throw ArgumentError('Invalid padding');
        }
        Uint8List validBytes = Uint8List.sublistView(
            decryptedBytes, 0, decryptedBytes.length - paddingLength);
        await decryptedFile!.writeAsBytes(validBytes);
      }
    } catch (e) {
      Fluttertoast.showToast(
          msg: type == 0
              ? 'encrypt failed'.t(context)
              : 'decrypt failed'.t(context));
      return false;
    }
    return null;
  }

  BlockCipher _createAESCipher(Uint8List key, Uint8List iv) {
    try {
      return CBCBlockCipher(AESEngine())
        ..init(true, ParametersWithIV(KeyParameter(key), iv));
    } catch (e) {
      throw ArgumentError('创建AES Cipher时发生错误: $e');
    }
  }

  StreamCipher _createRC4Cipher(Uint8List key, Uint8List? iv) {
    try {
      return RC4Engine()..init(true, KeyParameter(key));
    } catch (e) {
      throw ArgumentError('创建RC4 Cipher时发生错误: $e');
    }
  }
}
